﻿using System;
using System.Collections.Generic;

using Microsoft.Xna.Framework;

using FarseerPhysics.Factories;
using FarseerPhysics.Dynamics;
using FarseerPhysics.Collision;

using ZoeEngine;
using ZoeEngine.Framework;
using ZoeEngine.Framework.Collision;
using ZoeEngine.Services.Physics;

namespace ZoeEngine.Components.Physics
{
    public class PhysBodyComponent : BaseSpatialComponent
    {
        private PhysicsProvider _physicsProvider = null;

        private Body _body = null;

        private List<PhysShape> _shapesList = new List<PhysShape>();
        private CollisionType _bodyType = 0;
        private bool _fixedRotation = false;
        private Vector2 _position = Vector2.Zero;
        private float _rotation = 0.0f;
        private Vector2 _velocity = Vector2.Zero;

        internal void BuildCollisionShapes()
        {
            foreach (Fixture fix in _body.FixtureList)
            {
                _body.DestroyFixture(fix);
            }

            foreach (PhysShape shape in _shapesList)
            {
                shape.AttachShape(this);
            }
        }

        public override void Initialize()
        {
            base.Initialize();
        }
        public override void Start()
        {
            base.Start();

            _physicsProvider = Zoe.GetService<IPhysicsService>() as PhysicsProvider;
            if (_physicsProvider == null)
            {
                throw new ArgumentException("Could not locate appropriate service or provider is of incorrect type.");
            }

            // Register with the physics provider service.
            _body = BodyFactory.CreateBody(_physicsProvider.World, _position, this);
            this.BuildCollisionShapes();

            // Set body type,
            _body.BodyType = (BodyType)_bodyType;
            // Set initial velocity.
            _body.LinearVelocity = _velocity;
            // Set initial rotation.
            _body.Rotation = _rotation;
            _body.FixedRotation = _fixedRotation;
        }

        public override Vector2 Position
        {
            get
            {
                return (_body != null) ? Utility.ToPixels(_body.Position) : Utility.ToPixels(_position);
            }
            set
            {
                _position = Utility.ToMeters(value);
                if (_body != null)
                    _body.SetTransform(Utility.ToMeters(value), _body.Rotation);
            }
        }
        public override float Rotation
        {
            get
            {
                return (_body != null) ? MathHelper.ToDegrees(_body.Rotation) : MathHelper.ToDegrees(_rotation);
            }
            set
            {
                _rotation = MathHelper.ToRadians(value);
                if (_body != null)
                    _body.SetTransform(_body.Position, MathHelper.ToRadians(value));
            }
        }
        public override Vector2 Velocity
        {
            get
            {
                return (_body != null) ? Utility.ToPixels(_body.LinearVelocity) : Utility.ToPixels(_velocity);
            }
            set
            {
                _velocity = Utility.ToMeters(value);
                if (_body != null)
                    _body.LinearVelocity = Utility.ToMeters(value);
            }
        }

        internal Body Body
        {
            get
            {
                return _body;
            }
            set
            {
                _body = value;
            }
        }
        public CollisionType CollisionType
        {
            get
            {
                return (_body != null) ? (CollisionType)_body.BodyType : _bodyType;
            }
            set
            {
                _bodyType = value;
                if (_body != null)
                    _body.BodyType = (BodyType)value;
            }
        }
        public List<PhysShape> CollisionShapes
        {
            get
            {
                return _shapesList;
            }
            set
            {
                _shapesList = value;
                if (_body != null)
                    this.BuildCollisionShapes();
            }
        }
        public bool FixedRotation
        {
            get
            {
                return (_body != null) ? _body.FixedRotation : _fixedRotation;
            }
            set
            {
                _fixedRotation = value;
                if (_body != null)
                    _body.FixedRotation = value;
            }
        }
    }

    public enum CollisionType
    {
        Static = 0,
        Kinematic = 1,
        Dynamic = 2
    }
}
